# coding: utf-8
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from django.db import models
from django.http import JsonResponse

from lib.common import BasicManager
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from services.datamodel.student.models import Student, mm_Student
from services.datamodel.role.models import Role, mm_Role
from services.datamodel.delivery.models import DynamicDelivery, Delivery
from lib.live.LiveMain import LiveServers
from lib.live.Im import ImMain
import json
import random
from apps.student.share import app_logger
from django.db import transaction
from django.db.models import Q, Count, Sum, Avg, F
import traceback
from django.db import IntegrityError

class ModelManagerLive(BasicManager):
    # 获取获取直播列表
    def get_live_list(self, page, theme=None, mobile=None, types=None, user_id=None):
        result = self.filter(is_show=0).values("id", "theme", "name", "start_time", "status", "thumb", "student__mobile",
                                               "student__nick_name", "play_address",
                                               "real_start_time", "live_types").order_by("-created_at")
        if theme:
            result = result.filter(theme__contains=theme)
        if mobile:
            result = result.filter(student__mobile=mobile)
        if types:
            if int(types) == 2:
                result = result.filter(status__in=[2, 4])
            else:
                result = result.filter(status=types)
        if user_id:
            result = result.filter(student_id=user_id)
        result = list(result)
        for i in result:
            live_data = mm_LiveData.filter(live_id=i['id']).first()
            i['total_time'] = live_data.length_of_time if live_data else 0
        paginator = Paginator(result, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_live(self, live_id, user_id=None):
        result = self.filter(id=int(live_id)).values()
        if not result:
            return {}
        if user_id:
            result = result.filter(student_id=user_id)
        live_data = mm_LiveData.filter(live_id=live_id).first()
        total_time = live_data.length_of_time if live_data else 0
        live_info = result.first()
        live_info['total_time'] = total_time
        goods_sku = mm_LiveGoods.get_live_sku_goods(live_id)
        playback = mm_LivePlayback.filter(live_id=live_id).values()
        user_info = mm_Student.filter(pk=result[0]['student_id']).values("nick_name", "avatar", "nick_name", "id").first()
        return {"live_info": live_info, "goods_sku": goods_sku, 'playback': list(playback), 'user_info': user_info}

    def update_live(self, live_id, user_id, theme=None, poster=None, start_time=None, goods_id=None, thumb=None,
                    name=None, types=0, status=None, is_custom=0, qr_code=None):
        """
        修改直播
        :param live_id:
        :param user_id:
        :param theme:
        :param poster:
        :param start_time:
        :param goods_id:
        :param thumb:
        :return:
        """
        res = self.filter(pk=live_id, student_id=user_id).update(
            theme=theme, poster=poster, start_time=start_time, thumb=thumb, name=name, types=types, status=status,
            is_custom=is_custom, qr_code=qr_code
        )
        if res and goods_id:
            goods_id = json.loads(goods_id)
            old_goods_id = mm_LiveGoods.filter(live_id=live_id).values_list('goods', flat=True)
            goods_to_add = [user for user in goods_id if user not in old_goods_id]  # 需要添加的
            goods_to_del = list(set(old_goods_id).difference(set(goods_id)))  # 需要删除的
            mm_LiveGoods.filter(live_id=live_id, goods__in=goods_to_del).update(status=1)
            for v in goods_to_add:
                goods = mm_Role.filter(id=v).values().first()
                object, created = mm_LiveGoods.update_or_create(
                    live_id=live_id,
                    goods_id=v,
                    defaults={'charge': goods['charge']},
                    status=0
                )
            return {'retcode': 0, 'msg': 'OK'}
        return {'retcode': 1, 'msg': '修改失败'}

    def create_live(self, user_id, theme, name, poster, start_time, goods_id, room_id, live_types, types, thumb,
                    qr_code, is_custom=0):
        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                resObj = self.create(
                    student_id=user_id,
                    theme=theme,
                    name=name,
                    poster=poster,
                    start_time=start_time,
                    room_id=room_id,
                    stream_name=user_id,
                    live_types=live_types,
                    types=types,
                    thumb=thumb,
                    qr_code=qr_code,
                    is_custom=is_custom
                )
                goos_data = []
                for v in json.loads(goods_id):
                    goods = mm_Role.filter(id=v).first()
                    if goods:
                        object, created = mm_LiveGoods.update_or_create(
                            live_id=resObj.id,
                            goods_id=v,
                            defaults={'charge': goods.charge}
                        )
                        goos_data.append({'name': goods.name, 'charge': goods.charge, 'thumb': str(goods.thumb)})
                        if goods.sku:
                            t_stock = 0
                            for vs in json.loads(goods.sku):
                                s_obj = mm_LiveGoodsSku.create(
                                    live_goods_id=object.id,
                                    name=vs['name'],
                                    charge=vs['charge']
                                )
                                t_stock += s_obj.stock
                            object.stock = t_stock
                            object.save()
                # 创建腾讯云直播
                nuw_sttime = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")+timedelta(days=1)
                play_url, push_url = self.get_push_and_play(streamname=f"{resObj.id}_{user_id}", str_time=str(nuw_sttime))
                resObj.play_address = json.dumps(play_url)
                resObj.push_address = json.dumps(push_url)
                # 创建录播
                res_rule = LiveServers().createLiveRecordRule(user_id, 109914)  # 34796这个模板id是实现创建好的
                app_logger.info(res_rule)
                # 创建im群
                if int(live_types) == 1:
                    s = mm_Student.filter(pk=user_id).values('nick_name').first()
                    ImMain().account_import(str(user_id), nickname=s['nick_name'], faceurl='')
                    res_group = self.create_group(user_id)
                    app_logger.info(res_group.text)
                    loads_group_res = json.loads(res_group.text)
                    if loads_group_res and loads_group_res['ErrorCode'] == 0:
                        mm_LiveGroup.create(
                            live_id=resObj.id,
                            name='momself_'+str(user_id),
                            student_id=user_id,
                            group_id=str(loads_group_res['GroupId']) + '_' + str(resObj.id),
                        )
                        resObj.room_id = loads_group_res['GroupId']
                    else:
                        transaction.savepoint_rollback(save_id)
                        return {'retcode': 1, 'msg': '创建直播失败'}
                else:
                    mm_LiveGroup.create(
                        live_id=resObj.id,
                        name='momself_' + str(user_id),
                        student_id=user_id,
                        group_id=str(room_id) + '_' + str(resObj.id),  # 这里的群id为自定义了，由房间号+直播主键ID
                    )
                resObj.save()
                transaction.savepoint_commit(save_id)
                datas = {'play_url': play_url, 'push_url': push_url, 'types': types, 'live_types': live_types,
                         'theme': theme, 'name': name, 'goos_data': goos_data, 'id': resObj.id}
                return {'retcode': 0, 'msg': 'OK', 'data': datas}
            except IntegrityError:
                err = traceback.format_exc()
                app_logger.error(err)
                transaction.savepoint_rollback(save_id)
                return {'retcode': 1, 'msg': '该时间已创建直播'}
            except:
                err = traceback.format_exc()
                app_logger.error(err)
                transaction.savepoint_rollback(save_id)
                return {'retcode': 1, 'msg': '创建直播失败'}

    def get_push_and_play(self, streamname, str_time):
        live = LiveServers()
        push_url = live.getPushUrl(streamname, 1, str_time)
        play_url = live.getPlayUrl(streamname, str_time)
        return play_url, push_url

    def create_group(self, userid):
        return ImMain().create_group(userid)

    def get_live_data(self, page, theme=None, live_id=None, export=None):
        result = self.values('id', 'student_id', 'student__nick_name', 'dynamic_delivery_id', 'delivery_id').order_by('-created_at')
        if theme:
            result = result.filter(theme__contains=theme)
        if live_id:
            result = result.filter(id=live_id)
        result = list(result)
        from services.datamodel.order.models import mm_Order
        for l in result:
            l['order_num'] = mm_Order.filter(live_id=l['id'], status=2).count()
            l['audience_num'] = mm_LiveImUser.filter(group__live_id=l['id']).count()
            l['conversion_rate'] = 0 if l['audience_num'] == 0 else l['order_num'] / l['audience_num']
        if export:
            from io import BytesIO
            from django.http import HttpResponse
            import xlwt
            ws = xlwt.Workbook(encoding="UTF-8")
            w = ws.add_sheet(u'数据')
            w.write(0, 0, u'班主任id')
            w.write(0, 1, u'班主任')
            w.write(0, 2, u'转化率(%)')
            w.write(0, 3, u'成单数量')
            w.write(0, 4, u'观看人数')
            w.write(0, 5, u'活码id')
            w.write(0, 6, u'投放id')
            excel_row = 1
            for obj in result:
                w.write(excel_row, 0, obj['student_id'])
                w.write(excel_row, 1, obj['student__nick_name'])
                w.write(excel_row, 2, obj['conversion_rate'])
                w.write(excel_row, 3, obj['order_num'])
                w.write(excel_row, 4, obj['audience_num'])
                w.write(excel_row, 5, obj['dynamic_delivery_id'])
                w.write(excel_row, 6, obj['delivery_id'])
                excel_row += 1
            sio = BytesIO()
            ws.save(sio)
            sio.seek(0)
            response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = 'attachment; filename=stu_info.xls'
            response.write(sio.getvalue())
            return response
        paginator = Paginator(result, 10)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_user_watch_live_info(self, s_id):
        """
        获取用户观看直播信息
        @param s_id: student_id
        @return:
        """
        from django.db.models import Count, Sum
        from services.datamodel.order.models import mm_Order
        info = mm_LiveImUser.filter(student_id=s_id).aggregate(times=Count('student'), watch_time=Sum('watch_time'), like_times=Sum('like'))
        info['order_num'] = mm_Order.filter(user_id=s_id, status=2).count()  # 共计下单数
        info['comment_num'] = mm_LiveImMsg.filter(from_account_id=s_id).count()  # 共计评价

        live_list = list(mm_LiveImUser.filter(student_id=s_id).values(
            'group__live_id', 'group__live__theme', 'group__live__thumb', 'watch_time', 'like', 'group__live__real_start_time'))

        for l in live_list:
            l['orders_num'] = mm_Order.filter(user_id=s_id, status=2, live_id=l['group__live_id']).count()
            l['comment_num'] = mm_LiveImMsg.filter(from_account_id=s_id, group__live_id=l['group__live_id']).count()
            live_data = mm_LiveData.filter(live_id=l['group__live_id']).first()
            l['length_of_time'] = live_data.length_of_time if live_data else 0

        info.update({"live_list": list(live_list)})
        return info

    def get_statistical_data(self, live_id):
        """
        直播总数据
        @param live_id: 直播id
        @return:
        """
        from services.datamodel.order.models import mm_Order
        from decimal import Decimal
        live_data = {}  # 直播数据
        source_num = {}  # 来源人数（uv）
        replay_data = {}  # 回放数据
        source_conversion_rate = {}  # 来源转化率

        live_obj = self.get(id=live_id)
        data = mm_LiveData.filter(live_id=live_id).values().first()
        if not data:
            data = {}
        start_date = live_obj.real_start_time if live_obj.real_start_time else live_obj.start_time
        end_date = start_date + relativedelta(minutes=5, seconds=data.get('length_of_time', 0)) # 回调延迟，统计时间往后延迟5分钟
        live_time = [start_date, end_date]  # 直播时间段
        total_watch_num = mm_LiveImUser.filter(group__live_id=live_id).count()  # 直播总人数，包括回放人数
        total_order_num = mm_Order.filter(live_id=live_id, status=2).count()  # 成单总量，包括回放成单量

        watch_data = mm_LiveImUser.filter(group__live_id=live_id, like__gt=0, created_at__range=live_time).aggregate(
            # total_time=Sum('watch_time'),  # 总时长
            total_like=Sum('like'),  # 总点赞数
            like_num=Count('student_id')  # 点赞人数
        )
        # 2021-12-23 18:07:17笑纳说详情和数据统计直播时长都是主播直播的总时长
        watch_data['total_time'] = data.get('length_of_time') if data else 0
        comment_times = mm_LiveImMsg.filter(
            group__live_id=live_id, created_at__lte=end_date).count()  # 评论次数
        tally_times = mm_LiveTally.filter(
            live_id=live_id, types=0, created_at__lte=end_date).count()  # 购物袋点击次数
        order_deal_quantity = mm_Order.filter(
            live_id=live_id, status=2, created_at__lte=end_date).count()  # 订单成交量
        comment_num = mm_LiveImMsg.filter(
            group__live_id=live_id, created_at__lte=end_date).values('from_account_id').distinct().count()  # 评论人数
        order_deal_num = mm_Order.filter(
            live_id=live_id, status=2, created_at__lte=end_date).values('user_id').distinct().count()  # 订单人数
        avg_wacth_time = mm_LiveImUser.filter(
            group__live_id=live_id, created_at__lte=end_date).aggregate(avg_wacth_time=Avg('watch_time'))  # 人均观看时长
        live_data['total_num'] = data.get('uv', 0)  # 观看uv
        live_data['total_times'] = data.get('pv', 0)  # 观看次数
        live_data['highest_online'] = mm_LiveData.get_highest_online(live_id)  # 最高在线
        live_data.update(watch_data)
        live_data.update(avg_wacth_time)
        live_data['tally_times'] = tally_times
        live_data['comment_num'] = comment_num
        live_data['comment_times'] = comment_times
        live_data['order_deal_num'] = order_deal_num
        live_data['order_deal_quantity'] = order_deal_quantity

        re_tally_times = mm_LiveTally.filter(  # 回放购物袋点击次数
            Q(live_id=live_id) & Q(types=0) & Q(created_at__gte=end_date)).count()
        re_order_deal_quantity = mm_Order.filter(  # 回放订单成交量
            Q(live_id=live_id) & Q(status=2) & Q(created_at__gte=end_date)).count()
        re_avg_wacth_time = mm_LiveImUser.filter(  # 回放人均观看时长
            Q(group__live_id=live_id) & Q(created_at__gte=end_date)).aggregate(avg_wacth_time=Avg('watch_time'))
        re_order_deal_num = mm_Order.filter(  # 回放订单人数
            Q(live_id=live_id) & Q(status=2) & Q(created_at__gte=end_date)).values('user_id').distinct().count()
        replay_data.update(re_avg_wacth_time)
        replay_data['playback_uv'] = data.get('playback_uv', 0)  # 回放观看uv
        replay_data['playback_pv'] = data.get('playback_pv', 0)  # 回放次数
        replay_data['re_tally_times'] = re_tally_times
        replay_data['re_order_deal_num'] = re_order_deal_num
        replay_data['re_order_deal_quantity'] = re_order_deal_quantity

        shopping_data = list(mm_LiveGoods.get_goods_for_live_id(live_id))  # 购物袋数据
        for g in shopping_data:  # 商品下单量
            g['num'] = mm_Order.filter(live_id=live_id, goods_id=g['goods_id'], status=2).count()
        # 活码来源人数
        dynamic_delivery_num = list(mm_LiveImUser.filter(
            group__live_id=live_id,
            student__studentchannel__launch_dynamic_id__gt=0,
        ).values('student__studentchannel__launch_dynamic_id').annotate(num=Count('student__studentchannel__launch_dynamic_id')))
        # 投放来源人数
        delivery_num = list(mm_LiveImUser.filter(
            group__live_id=live_id,
            student__studentchannel__launch_id__gt=0,
        ).values('student__studentchannel__launch_id').annotate(num=Count('student__studentchannel__launch_id')))
        # 非投放来源人数
        other_num = total_watch_num - sum([i.get('num') for i in dynamic_delivery_num]) - sum([i.get('num') for i in delivery_num])
        source_num['other_num'] = other_num
        source_num['delivery_num'] = delivery_num
        source_num['dynamic_delivery_num'] = dynamic_delivery_num
        # 投放订单转化率列表
        delivery_rate = []
        for i in delivery_num:
            d_id = i['student__studentchannel__launch_id']
            order_num = mm_Order.filter(live_id=live_id, status=2, user__studentchannel__launch_id=d_id).count()
            delivery_rate.append({"delivery_id": d_id, "rate": order_num / i['num']})
        # 活码订单转化率列表
        dynamic_delivery_rate = []
        for i in dynamic_delivery_num:
            d_id = i['student__studentchannel__launch_dynamic_id']
            order_num = mm_Order.filter(live_id=live_id, status=2, user__studentchannel__launch_dynamic_id=d_id).count()
            dynamic_delivery_rate.append({"dynamic_delivery_id": d_id, "rate": order_num / i['num']})
        # 非投放订单量
        other_order_num = total_order_num - mm_Order.filter(
            Q(live_id=live_id) &
            Q(status=2) &
            (Q(user__studentchannel__launch_dynamic_id__gt=0) | Q(user__studentchannel__launch_id__gt=0))
        ).count()
        # 非投放转化率
        other_rate = (other_order_num / other_num) if other_num != 0 else 0
        source_conversion_rate['other_rate'] = other_rate
        source_conversion_rate['delivery_rate'] = delivery_rate
        source_conversion_rate['dynamic_delivery_rate'] = dynamic_delivery_rate

        return {"live_data": live_data, 'replay_data': replay_data, 'shopping_data': shopping_data,
                'source_conversion_rate': source_conversion_rate, 'source_num': source_num}

    def get_online_data(self, live_id, start_date=None, end_date=None):
        """
        获取实时在线数据
        @param live_id:
        @param start_date:
        @param end_date:
        @return:
        """
        from services.datamodel.order.models import mm_Order
        live = self.filter(pk=live_id).first()
        if live.status == 1:
            return []
        live_data = mm_LiveData.filter(live=live).first()
        if not start_date and not end_date:
            start_date = live.real_start_time if live.real_start_time else live.start_time
            if live_data and live_data.length_of_time and int(live.status) == 3:
                end_date = start_date + relativedelta(seconds=live_data.length_of_time)
            else:
                end_date = datetime.now()
        else:
            start_date = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S")
            end_date = datetime.strptime(end_date, "%Y-%m-%d %H:%M:%S")
        online_data = []
        while start_date <= end_date:
            range_time = [start_date - relativedelta(minutes=5), start_date]
            # 订单量
            order_num = mm_Order.filter(live_id=live_id, status=2, created_at__range=range_time).count()
            # 转发量
            forward_num = mm_LiveTally.filter(live_id=live_id, types=1, created_at__range=range_time).count()
            # 购物袋点击量
            click_num = mm_LiveTally.filter(live_id=live_id, types=0, created_at__range=range_time).count()
            # 在线人数， 流失人数
            online_num = mm_LivePeopleFlow.filter(
                live_id=live_id,
                join_time__lte=int(datetime.timestamp(start_date))).filter(
                Q(exit_time__gte=int(datetime.timestamp(start_date)) ,status=1) |
                Q(status=0)
            ).values("student_id").distinct().count()
            lose_num = mm_LivePeopleFlow.filter(live_id=live_id).filter(
                status=1,
                exit_time__gte=int(datetime.timestamp(start_date-relativedelta(minutes=5))),
                exit_time__lte=int(datetime.timestamp(start_date))
            ).values("student_id").distinct().count()
            data = {
                'time': start_date,
                'order_num': order_num,
                'forward_num': forward_num,
                'click_num': click_num,
                'online_num': online_num,
                'lose_num': lose_num,
            }
            online_data.append(data)
            # 时间粒度设置为5分钟
            start_date += relativedelta(minutes=5)
        return online_data

    def update_live_status(self, status, live_id=None, room_id=None):
        if live_id:
            result = self.get_or_default(pk=live_id)
            result.status = status
            result.save()
            # 主播结束直播，需要服务端主动解散房间
            if status == 3:
                # # 解散IM群组
                # ImMain().destroy_group(result.room_id)
                # 解散trtc房间
                import time
                h = (datetime.now()+timedelta(hours=-6)).strftime("%Y-%m-%d %H:%M:%S")
                StartTime = int(time.mktime(time.strptime(h, '%Y-%m-%d %H:%M:%S')))
                EndTime = int(time.time())
                res = LiveServers().getRoomInfoForCommId(StartTime=StartTime, EndTime=EndTime, RoomId=result.room_id)
                if res['Total'] <= 0:
                    return
                for v in res['RoomList']:
                    # 如果房间未结束，服务端主动结束直播
                    if v['RoomString'] == result.room_id and not v['IsFinished']:
                        LiveServers().dismissRoomByStrRoomId(RoomId=int(result.room_id))
                        break
        if room_id:
            import time
            result = self.get_or_default(room_id=room_id, status=1)
            if not result:
                # 意外退出后重新开播
                result = self.get_or_default(room_id=room_id, status=4)
            result.status = status
            if not result.real_start_time:
                t = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
                result.real_start_time = t
            result.save()
            # 推流后发送自定义消息
            if int(result.live_types) == 1:
                res = ImMain().send_group_msg(room_id, 12, 3).json()
                app_logger.error(res)
            # 添加虚拟评论到定时器任务
            mm_LiveFictitiousComment.add_comment_to_timed_task(result.id)
            live_data, _ = mm_LiveData.get_or_create(live_id=result.id)

    def send_msg(self, live_id, command, msg):
        """
        以管理员身份发送普通消息
        @param live_id:
        @return:
        """
        group_id = self.get(pk=live_id).room_id
        res = ImMain().send_group_msg(group_id, command, msg).json()
        if res.get('ErrorCode') != 0:
            app_logger.error("管理员发送普通消息失败：{}".format(res))
            return res

    def get_fictitious_data(self, live_id, types):
        """
        虚拟数据
        @param types: 1:虚拟购买  2:虚拟转发
        @param live_id:
        @return:
        """
        live = self.filter(pk=live_id).first()
        if types == 1:
            num = live.fictitious_pay
        elif types == 2:
            num = live.fictitious_forward
        else:
            num = 10
        res = random.sample(list(mm_Student.filter(nick_name__isnull=False, avatar__isnull=False).values('nick_name', 'avatar')),num)
        return res

    def get_online_num(self, live_id):
        """
        获取直播群在线人数
        @param live_id:
        @return:
        """
        live = self.filter(id=live_id).first()
        res = ImMain().get_online_member_num(live.room_id).json()
        if res['ErrorCode'] == 0:
            return JsonResponse({"retcode": 0, "data": res['OnlineMemberNum']})
        app_logger.error(f"群组{live_id}在线人数查询：{res}")
        return JsonResponse({"retcode": 1, "message": res.get('ErrorInfo')})

class ModelManagerLiveGoods(BasicManager):

    def get_live_goods(self, page, live_id):
        """
        直播课程列表
        :param user_id:
        :param live_id:
        :return:
        """
        result = self.filter(live_id=live_id, status=0).select_related("live_goods", "goods").values("goods_id", "charge", "stock",
                                                                                           "goods__name", "goods__thumb", 'goods__original_charge',
                                                                                           "id") \
            .order_by("-created_at")
        if not page:
            return {'retcode': 0, 'retlist': list(result)}
        paginator = Paginator(result, 5)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        for v in result_page:
            skus = mm_LiveGoodsSku.filter(live_goods_id=v['id']).values('id', 'charge', 'stock', 'name')
            if skus:
                key_of_min_val = min(skus, key=lambda x: x['charge'])
                v['charge'] = key_of_min_val['charge']
                v['stock'] = key_of_min_val['stock']

        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages, 'count': paginator.count}

    def course_detail(self, live_id, goods_id):
        """
        直播课程详情
        :param live_id:
        :param goods_id:
        :return:
        """
        goods = mm_LiveGoods.filter(goods_id=goods_id, live_id=live_id).select_related("live_goods", "goods") \
            .values('goods__name', 'goods__id',
                    'goods__original_charge', 'charge',
                    'goods__desc', 'goods__thumb',
                    'goods__detail', 'stock', 'id',
                    'live_goods__id').first()
        if not goods:
            return
        goods_detail = {'name': goods['goods__name'], 'desc': goods['goods__desc'], 'thumb': str(goods['goods__thumb']),
                        'detail': goods['goods__detail'], 'original_charge': goods['goods__original_charge']}
        if not goods['live_goods__id']:
            goods_detail['charge'] = goods['charge']  # stock
            goods_detail['stock'] = goods['stock']
            goods_detail['sku_detail'] = []
        else:
            skus = mm_LiveGoodsSku.filter(live_goods_id=goods['id']).values('id', 'charge', 'stock', 'name')
            key_of_min_val = min(skus, key=lambda x: x['charge'])
            goods_detail['charge'] = key_of_min_val['charge']
            goods_detail['stock'] = key_of_min_val['stock']
            # sku
            goods_detail['sku_detail'] = list(skus)
        return goods_detail

    def add_course_to_live(self, goods_id, live_id):
        """
        添加直播课程
        :param goods_id:
        :param live_id:
        :return:
        """
        ids = json.loads(goods_id)
        for v in ids:
            goods = mm_Role.filter(id=v).values('charge', 'id', 'sku').first()
            obj = mm_LiveGoods.create(
                live_id=live_id,
                charge=goods['charge'],
                goods_id=goods['id']
            )
            if goods.get('sku'):
                t_stock = 0
                for vs in json.loads(goods.get('sku')):
                    s_obj = mm_LiveGoodsSku.create(
                        live_goods=obj,
                        name=vs.get('name'),
                        charge=vs.get('charge')
                    )
                    t_stock += s_obj.stock
                obj.stock = t_stock
                obj.save()

    def get_live_sku_goods(self, live_id):
        """
        获取sku商品列表
        @param live_id:
        @return:
        """
        goods_obj = self.filter(live_id=live_id, status=0).select_related("goods").values(
            'id', 'goods__name', 'stock', 'charge', 'goods__original_charge', 'goods__thumb', 'goods_id'
        )
        for good in goods_obj:
            if mm_LiveGoodsSku.filter(live_goods_id=good['id']).exists():
                goods_sku = mm_LiveGoodsSku.filter(live_goods_id=good['id']).values("id", "name", "charge", "stock")
                good['sku'] = list(goods_sku)
            else:
                good['sku'] = []
        return list(goods_obj)

    def update_goods(self, goods_sku):
        """
        编辑商品库存和价格
        @param goods_sku:[{"id": 3, "good_name": "小班课卡", "stock": 20, "charge": 99, "sku": []}]
        @return:
        """
        try:
            with transaction.atomic():
                for g_sku in goods_sku:
                    if g_sku.get('sku'):
                        for s in g_sku['sku']:
                            mm_LiveGoodsSku.filter(id=s['id']).update(charge=s['charge'], stock=s['stock'])
                        self.filter(id=g_sku['id']).update(stock=sum([int(i.get('stock')) for i in g_sku['sku']]))
                    else:
                        self.filter(id=g_sku['id']).update(charge=g_sku['charge'], stock=g_sku['stock'])
                return True
        except Exception as e:
            app_logger.error(e)
            return False

    def get_goods_for_live_id(self, live_id):
        res = self.filter(live_id=live_id, status=0).values(
            'goods_id', 'goods__card_name', 'goods__card_name', 'pv', 'uv', 'browse_time'
        )
        return res

    def push_goods(self, live_id, goods_id):
        """
        后台推送商品到客户端
        @param live_id:
        @param goods_id:
        @return:
        """
        from django.core.cache import cache
        group_id = mm_Live.get(pk=live_id).room_id
        res = ImMain().send_group_msg(group_id, 9, goods_id).json()
        if res.get('ErrorCode') != 0:
            app_logger.error(res)
            return {"retcode": 1, 'message': '推送失败', "data": res}
        cache.set(f"{group_id}_push_goods", goods_id, 3600*24)
        return {"retcode": 0, 'message': '推送成功'}


class ModelManagerLiveGroup(BasicManager):

    def get_group(self, live_id, user_id=None, group_id=None):
        result = self.filter(live_id=live_id).values().first()
        if user_id:
            result = result.filter(student_id=user_id)
        if group_id:
            result = result.filter(group_id=group_id)
        return result


class ModelManagerLiveImMsg(BasicManager):

    def get_user_comment(self, page, student_id, live_id):
        """
        获取用户评论
        @param page:
        @param student_id:
        @param live_id:
        @return:
        """
        result = self.filter(from_account_id=student_id, group__live_id=live_id).values()
        paginator = Paginator(result, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_msg_list(self, page, live_id, is_forbidden, nick_name=None, mobile=None, headmaster_id=None, msg_start_date=None,
                     msg_end_date=None):
        """获取直播间所有评论"""
        result = self.filter(
            Q(group__live_id=live_id) & Q(from_account__group_user__group__live_id=live_id) &
            Q(from_account__group_user__is_forbidden__in=json.loads(is_forbidden))
        ).select_related("from_account").values(
            'id', 'from_account__nick_name', 'from_account__mobile', 'from_account__avatar', 'msg_time', 'msg_body',
            'from_account__headmaster__nick_name', 'from_account__group_user__is_forbidden', "from_account_id",
            'group_id', 'created_at', 'from_account__be_invited__invitation__nick_name'
        ).order_by('-created_at')
        if nick_name:
            result = result.filter(from_account__nick_name__contains=nick_name)
        if mobile:
            result = result.filter(from_account__mobile=mobile)
        if headmaster_id:
            result = result.filter(from_account__headmaster_id=headmaster_id)
        if msg_start_date and msg_end_date:
            result = result.filter(msg_time__range=[msg_start_date, msg_end_date])
        # result = list(result)
        # for i in result:
        #     invitation_user = mm_LiveInvitationUser.filter(be_invited_id=i['from_account_id'], live_id=live_id).first()
        #     i['from_account__be_invited__invitation__nick_name'] = invitation_user.invitation.nick_name if invitation_user else None
        paginator = Paginator(result, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def handle_like(self, live_id, user_id):
        pass


class ModelManagerLiveImUser(BasicManager):

    def update_forbidden_words(self, is_forbidden, live_id, group_id, student_id):
        """
        禁言更新
        @param is_forbidden: 0：解除禁言  1：禁言
        @param livr_id:    直播间id
        @param group_id:   群聊id
        @param student_id: 学生id  members
        @return:
        """
        im_user = mm_LiveImUser.get(group__live_id=live_id, group_id=group_id, student_id=student_id)
        groupid = im_user.group.live.room_id  # 此groupid为创建时腾讯云给出的id
        shutuptime = 0 if int(is_forbidden) == 0 else 4294967295  # 默认永久禁言
        res = ImMain().forbid_send_msg(groupid, [student_id], shutuptime).json()
        if res.get('ErrorCode') == 0:
            im_user.is_forbidden = is_forbidden
            im_user.save()
            return {"retcode": 0, 'message': 'OK'}
        else:
            app_logger.error(res)
            return {"retcode": 1, 'message': '更改失败'}

    def get_watch_user_list(self, page, live_id, is_order=None, export=None, nick_name=None, headmaster_id=None, parent=None):
        """
        获取观看直播用户列表
        @param page:
        @param live_id: 直播id
        @param is_order: 0：倒序，1：正序
        @param export:  1：导出
        @param nick_name:   用户昵称
        @param headmaster_id:   班主任id
        @param parent:   上级邀请人
        @return:
        """

        result = self.filter(
            group__live_id=live_id
        ).select_related("student").values(
            'student_id', 'watch_time', 'student__nick_name', 'student__mobile', 'student__avatar', 'created_at',
            'student__headmaster__nick_name', 'student__age', 'student__occupation', 'student__districtname',
            'student__be_invited__invitation__nick_name', 'student__provincename', 'student__cityname'
        ).order_by('-created_at')
        if nick_name:
            result = result.filter(student__nick_name__contains=nick_name)
        if headmaster_id:
            result = result.filter(student__headmaster_id=headmaster_id)
        if parent:
            result = result.filter(student__be_invited__invitation__nick_name=parent)
            # stu = mm_LiveInvitationUser.filter(live_id=live_id, invitation__nick_name__contains=parent).values("be_invited_id")
            # result = result.filter(student_id__in=[i['be_invited_id'] for i in stu], group__live_id=live_id)
        if is_order == '0':
            result = result.order_by('-watch_time')
        elif is_order == '1':
            result = result.order_by('watch_time')
        # result = list(result)
        # for i in result:
        #     i['invitees_num'] = mm_LiveInvitationUser.filter(live_id=live_id, invitation_id=i['student_id']).count()
        #     invitation_user = mm_LiveInvitationUser.filter(be_invited_id=i['student_id'], live_id=live_id).first()
        #     i['student__be_invited__invitation__nick_name'] = invitation_user.invitation.nick_name if invitation_user else None
        if export:
            from io import BytesIO
            from django.http import HttpResponse
            import xlwt
            ws = xlwt.Workbook(encoding="UTF-8")
            w = ws.add_sheet(u'数据')
            w.write(0, 0, u'用户昵称')
            w.write(0, 1, u'用户手机号')
            w.write(0, 2, u'用户头像')
            w.write(0, 3, u'首次进来时间')
            w.write(0, 4, u'观看时长')
            w.write(0, 5, u'班主任')
            w.write(0, 6, u'观看邀请人')
            w.write(0, 7, u'用户邀请好友')
            w.write(0, 8, u'年龄')
            w.write(0, 9, u'职业')
            w.write(0, 10, u'地区')
            excel_row = 1
            for obj in result:
                invitees_num = mm_LiveInvitationUser.filter(live_id=live_id, invitation_id=obj['student_id']).count()
                w.write(excel_row, 0, obj['student__nick_name'])
                w.write(excel_row, 1, obj['student__mobile'])
                w.write(excel_row, 2, obj['student__avatar'])
                w.write(excel_row, 3, obj['created_at'])
                w.write(excel_row, 4, obj['watch_time'])
                w.write(excel_row, 5, obj['student__headmaster__nick_name'])
                w.write(excel_row, 6, obj['student__be_invited__invitation__nick_name'])
                w.write(excel_row, 7, invitees_num)
                w.write(excel_row, 8, obj['student__age'])
                w.write(excel_row, 9, obj['student__occupation'])
                w.write(excel_row, 10, obj['student__districtname'])
                excel_row += 1
            sio = BytesIO()
            ws.save(sio)
            sio.seek(0)
            response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = 'attachment; filename=stu_info.xls'
            response.write(sio.getvalue())
            return response
        paginator = Paginator(result, 10)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_user_for_group(self, live_id, user_id):
        """
        获取用户群信息
        :param live_id:
        :param user_id:
        :param group_id:
        :return:
        """
        result = self.filter(live_id=live_id, student_id=user_id).values().first()
        if not result:
            return {'retcode': 1, 'msg': '未加入群聊'}
        res = ImMain().get_group_info([result['group_id']])
        app_logger.info(res.text)
        loads_group_res = json.loads(res.text)
        if loads_group_res and loads_group_res['ErrorCode'] == 0:
            result['group_info'] = loads_group_res['GroupInfo']
        return {'retcode': 0, 'msg': 'OK', 'data': result}

    def get_live_users(self, page, group_id):
        """
        获取直播用户id---该功能用户直播结束统计用户观看时长使用
        :param page:
        :param group_id:
        :return:
        """
        result = self.filter(group_id=group_id).values('student_id')
        paginator = Paginator(result, 50)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}


class ModelManagerLiveTally(BasicManager):

    def get_shopping_data(self, page, live_id, nick_name=None, mobile=None, click_start_date=None, click_end_date=None,
                          headmaster_id=None, export=None):
        """
        购物袋数据
        @param page:
        @param live_id:
        @return:
        """
        result = self.filter(
            live_id=live_id, types=0
        ).select_related("student").values(
            "id", "student__nick_name", "student__mobile", "student__avatar", "created_at",
            "student__headmaster__nick_name", "student_id"
        ).order_by('-created_at')
        if nick_name:
            result = result.filter(student__nick_name__contains=nick_name)
        if mobile:
            result = result.filter(student__mobile=mobile)
        if click_start_date and click_end_date:
            result = result.filter(created_at__range=[click_start_date, click_end_date])
        if headmaster_id:
            result = result.filter(student__headmaster_id=headmaster_id)
        result = list(result)
        for i in result:
            invitation_user = mm_LiveInvitationUser.filter(be_invited_id=i['student_id'], live_id=live_id).first()
            i['student__be_invited__invitation__nick_name'] = invitation_user.invitation.nick_name if invitation_user else None
        if export:
            from io import BytesIO
            from django.http import HttpResponse
            import xlwt
            ws = xlwt.Workbook(encoding="UTF-8")
            w = ws.add_sheet(u'数据')
            w.write(0, 0, u'序号')
            w.write(0, 1, u'用户昵称')
            w.write(0, 2, u'用户手机号')
            w.write(0, 3, u'用户头像')
            w.write(0, 4, u'点击时间')
            w.write(0, 5, u'班主任')
            w.write(0, 6, u'观看邀请人')
            excel_row = 1
            for obj in result:
                w.write(excel_row, 0, obj['id'])
                w.write(excel_row, 1, obj['student__nick_name'])
                w.write(excel_row, 2, obj['student__mobile'])
                w.write(excel_row, 3, obj['student__avatar'])
                w.write(excel_row, 4, obj['created_at'])
                w.write(excel_row, 5, obj['student__headmaster__nick_name'])
                w.write(excel_row, 6, obj['student__be_invited__invitation__nick_name'])
                excel_row += 1
            sio = BytesIO()
            ws.save(sio)
            sio.seek(0)
            response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = 'attachment; filename=stu_info.xls'
            response.write(sio.getvalue())
            return response
        paginator = Paginator(result, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}

    def get_forward_data(self, page, live_id, nick_name=None, mobile=None, forward_start_date=None, forward_end_date=None,
                         headmaster_id=None, export=None):
        """转发数据"""
        result = self.filter(
            live_id=live_id, types=1
        ).select_related("student").values(
            'student_id', 'student__nick_name', 'student__mobile', 'student__avatar',
            'created_at', 'student__headmaster__nick_name', 'id'
        ).order_by('-created_at')
        if nick_name:
            result = result.filter(student__nick_name__contains=nick_name)
        if mobile:
            result = result.filter(student__mobile=mobile)
        if forward_start_date and forward_end_date:
            result = result.filter(created_at__range=[forward_start_date, forward_end_date])
        if headmaster_id:
            result = result.filter(student__headmaster_id=headmaster_id)
        result = list(result)
        for i in result:
            i['invitees_num'] = mm_LiveInvitationUser.filter(live_id=live_id, invitation_id=i['student_id']).count()
            invitation_user = mm_LiveInvitationUser.filter(be_invited_id=i['student_id'], live_id=live_id).first()
            i['student__be_invited__invitation__nick_name'] = invitation_user.invitation.nick_name if invitation_user else None
        if export:
            from io import BytesIO
            from django.http import HttpResponse
            import xlwt
            ws = xlwt.Workbook(encoding="UTF-8")
            w = ws.add_sheet(u'数据')
            w.write(0, 0, u'用户昵称')
            w.write(0, 1, u'用户手机号')
            w.write(0, 2, u'用户头像')
            w.write(0, 3, u'转发时间')
            w.write(0, 4, u'邀约人数')
            w.write(0, 5, u'班主任')
            w.write(0, 6, u'观看邀请人')
            excel_row = 1
            for obj in result:
                w.write(excel_row, 0, obj['student__nick_name'])
                w.write(excel_row, 1, obj['student__mobile'])
                w.write(excel_row, 2, obj['student__avatar'])
                w.write(excel_row, 3, obj['created_at'])
                w.write(excel_row, 4, obj['invitees_num'])
                w.write(excel_row, 5, obj['student__headmaster__nick_name'])
                w.write(excel_row, 6, obj['student__be_invited__invitation__nick_name'])
                excel_row += 1
            sio = BytesIO()
            ws.save(sio)
            sio.seek(0)
            response = HttpResponse(sio.getvalue(), content_type='application/vnd.ms-excel')
            response['Content-Disposition'] = 'attachment; filename=stu_info.xls'
            response.write(sio.getvalue())
            return response
        paginator = Paginator(result, 15)
        try:
            result_page = paginator.page(page)
        except PageNotAnInteger:
            result_page = paginator.page(1)
        except EmptyPage as e:
            return {'retlist': [], 'curpageidx': page,
                    'hasnext': False, 'hasprevious': False}
        return {'retlist': list(result_page), 'curpageidx': page,
                'hasnext': result_page.has_next(), 'hasprevious': result_page.has_previous(),
                'total_page': paginator.num_pages}


class ModelManagerLiveGoodsSku(BasicManager):
    pass


class ModelManagerLiveInvitationUser(BasicManager):
    pass


class ModelManagerLiveData(BasicManager):

    def get_highest_online(self, live_id):
        """
        获取直播最高在线人数
        @param live_id:
        @return:
        """
        live_date_obj = self.filter(live_id=live_id).first()
        if not live_date_obj:
            return 0
        return live_date_obj.highest_online

    def get_live_pv(self, live_id):
        from django.core.cache import cache
        if live_id:
            pv_sums = cache.get('live_pv_'+str(live_id))
            if pv_sums:
                return pv_sums
            res = self.filter(live_id=live_id).values('pv').first()
            if res:
                return res['pv']
            return False

class ModelManagerLiveFictitiousComment(BasicManager):

    def import_fictitious_comment(self, data, live_id):
        """
        导入虚拟评论
        @param data:excel数据
        @param live_id:
        @return:
        """
        try:
            with transaction.atomic():
                live = mm_Live.filter(pk=live_id).first()
                if live.status == 1:  # 未开播情况
                    self.filter(live_id=live_id).delete()
                    LiveFictitiousComment.objects.bulk_create([
                        LiveFictitiousComment(
                            live_id=live_id,
                            send_time=i[0],
                            comment=i[1], nick_name=i[2]) for i in data
                    ])
                elif live.status == 2:  # 已开播情况
                    from lib.timed_task import scheduler, TimedTaskClass
                    comments = self.filter(live_id=live_id).select_related("live")
                    # get_job方法在服务器中不确定能否获取到定时任务，有时无法移除任务，所以根据时间判断对未进行的任务直接delete
                    # 添加了2层保险，当remove_job不执行时，定时任务也会根据评论id是否还存在判断是否发送虚拟评论
                    for c in comments:
                        if live.real_start_time + timedelta(seconds=c.send_time) > datetime.now():
                            if scheduler.get_job(str(c.id)):
                                scheduler.remove_job(str(c.id))
                                app_logger.error(f'删除定时任务:{c.id}')
                            c.delete()
                    # 重新添加计时器任务
                    for i in data:
                        if live.real_start_time + timedelta(seconds=i[0]) > datetime.now():
                            c_obj = self.create(live=live, send_time=i[0], comment=i[1], nick_name=i[2])
                            msg = json.dumps({"comment": i[1], "nick_name": i[2]})
                            scheduler.add_job(
                                TimedTaskClass.send_msg, 'date',
                                run_date=live.real_start_time + timedelta(seconds=i[0]),
                                args=[live.room_id, 14, msg, c_obj.id], id=str(c_obj.id)
                            )
            return JsonResponse({"retcode": 0, "message": "导入成功"})
        except Exception as e:
            app_logger.error(e)
            return JsonResponse({"retcode": 1, "message": "导入失败"})

    def add_comment_to_timed_task(self, live_id):
        """
        添加虚拟评论到定时器任务
        @param live_id:
        @return:
        """
        comments = self.filter(live_id=live_id).select_related("live").values(
            'id', 'comment', 'nick_name', 'send_time', 'live__room_id', 'live__real_start_time'
        )
        if comments:
            from lib.timed_task import scheduler, TimedTaskClass
            try:
                for c in comments:
                    if not scheduler.get_job(str(c['id'])):
                        msg = json.dumps({"comment": c['comment'], "nick_name": c['nick_name']})
                        scheduler.add_job(
                            TimedTaskClass.send_msg, 'date',
                            run_date=c['live__real_start_time'] + timedelta(seconds=c['send_time']),
                            args=[c['live__room_id'], 14, msg, c['id']], id=str(c['id'])
                        )
                app_logger.error("添加虚拟评论到定时器任务成功！")
            except Exception as e:
                app_logger.error(f"添加虚拟评论到定时器任务失败: {e}")


class ModelManagerLivePlayback(BasicManager):

    def get_playback(self, live_id, passworld, user_id=None):
        res = self.filter(live_id=live_id, playback_pass=passworld).values('url', 'playback_pass').first()
        if res:
            from django.core.cache import cache
            if res['playback_pass'] == str(passworld):
                # 这是设置pv
                live_data = mm_LiveData.get_or_default(live_id=live_id)
                if not cache.get('live_uv_id:' + str(live_id) + ':' + str(user_id)):
                    live_data.playback_uv = F('playback_uv') + 1
                live_data.playback_pv = F('playback_pv') + 1
                cache.set('live_uv_id:' + str(live_id) + ':' + str(user_id), 1, 3600 * 24 * 15)
                live_data.save()
                return {'retcode': 0, 'msg': 'OK', 'data': res['url']}
        return {'retcode': 1, 'msg': '该密码不存在或者直播不存在'}


class ModelManagerLivePeopleFlow(BasicManager):
    pass


class Live(models.Model):
    student = models.ForeignKey(Student, related_name="blogger")
    theme = models.CharField("直播主题", max_length=50)
    name = models.CharField("直播副标题", max_length=150, default='', blank=True)
    is_show = models.PositiveSmallIntegerField("是否显示", default=0)
    types = models.PositiveSmallIntegerField("推流形式", default=0)  # 形式0默认   1竖屏
    live_types = models.PositiveSmallIntegerField("客户端直播类型", default=0)  # 0:客户端展示视频直播  1:展示推流直播
    desc = models.CharField("直播简介", max_length=200, blank=True)
    thumb = models.ImageField("直播主图", max_length=200, default='', blank=True)
    cover = models.ImageField("直播封面", max_length=200, default='', blank=True)   # 用于用户进入直播时暂停的封面
    detail = models.TextField("直播详情", default='', blank=True)
    start_time = models.DateTimeField("直播开始时间", null=True, blank=True)
    real_start_time = models.DateTimeField("实际直播开始时间", null=True, blank=True)
    status = models.PositiveSmallIntegerField("直播状态", default=1)  # 1默认未开播  2直播中  3直播结束  4直播意外中断
    # playback_url = models.CharField("直播回放", max_length=200, default='', blank=True)
    # playback_pass = models.CharField("回放密码", max_length=20, default='', blank=True)
    poster = models.CharField("直播分享码(海报)", max_length=200, default='', blank=True)
    qr_code = models.CharField("公众号二维码", max_length=200, default='', blank=True)
    pay_banner = models.PositiveSmallIntegerField("是否展示横幅", default=0, blank=True)
    fictitious_pay = models.IntegerField("虚拟购买人数", default=0, blank=True)
    forward_banner = models.PositiveSmallIntegerField("是否展示转发横幅", default=1, blank=True)
    fictitious_forward = models.IntegerField("虚拟转发人数", default=0, blank=True)
    is_clear = models.PositiveSmallIntegerField("是否展示清屏按钮", default=1, blank=True)
    is_address = models.PositiveSmallIntegerField("下单是否填写地址", default=1, blank=True)
    dynamic_delivery = models.ForeignKey(DynamicDelivery, null=True, blank=True)  # 活码id
    delivery = models.ForeignKey(Delivery, null=True, blank=True)  # 投放id
    push_address = models.TextField("推流地址")
    play_address = models.TextField("播放地址")
    delivery_start = models.DateTimeField("投放id开始时间", null=True, blank=True)
    delivery_end = models.DateTimeField("投放id结束时间", null=True, blank=True)
    room_id = models.CharField("房间号", max_length=30, unique=True)
    stream_name = models.CharField("流名称", max_length=30)
    is_custom = models.PositiveSmallIntegerField("是否自定义", default=0, blank=True)  # 0是默认, 1是自定义
    discount_start_time = models.DateTimeField("折扣开始时间", null=True, blank=True)
    discount_end_time = models.DateTimeField("折扣结束时间", null=True, blank=True)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLive()

    class Meta:
        verbose_name = 'Live'
        verbose_name_plural = verbose_name
        db_table = "momself_live"

    def __str__(self):
        return self.name


class LiveGoods(models.Model):
    live = models.ForeignKey(Live)
    goods = models.ForeignKey(Role, related_name="goods")
    charge = models.IntegerField('价格(该价格是直播时的价格，如果不去改默认原商品价格)', default=0)  # 单位：分
    stock = models.IntegerField("库存", default=500)
    pv = models.IntegerField("pv", default=0, blank=True)
    uv = models.IntegerField("uv", default=0, blank=True)
    browse_time = models.IntegerField("浏览时间(秒)", default=0, blank=True)
    status = models.PositiveSmallIntegerField("状态", default=0)  # 0默认可以卖 1不能卖
    # sku = models.TextField("商品sku", default='', blank=True)  # [{1: {'name': '思维', 'charge': 90}}]
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveGoods()

    class Meta:
        verbose_name = '直播商品表'
        verbose_name_plural = verbose_name
        db_table = "momself_live_goods"


class LiveGoodsSku(models.Model):
    live_goods = models.ForeignKey(LiveGoods, related_name="live_goods")
    name = models.CharField("sku名称", max_length=30)
    charge = models.IntegerField("价格", default=0)
    stock = models.IntegerField("库存", default=500)
    is_launched = models.BooleanField(default=True, verbose_name='是否上架销售')
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveGoodsSku()

    class Meta:
        verbose_name = '直播商品SKU表'
        verbose_name_plural = verbose_name
        db_table = "momself_live_goods_sku"


class LiveGroup(models.Model):
    live = models.ForeignKey(Live)
    name = models.CharField("群名称", max_length=30)
    student = models.ForeignKey(Student, related_name="audience")
    group_id = models.CharField("群id", max_length=50)
    # group_user_id = models.IntegerField("群用户标识id")
    # admins = models.ForeignKey(Student, related_name="administrators")
    types = models.PositiveSmallIntegerField("群类型", default=3)  # 0:public 1:Private 2:ChatRoom 3:AVChatRoom
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveGroup()

    class Meta:
        verbose_name = '直播im群'
        verbose_name_plural = verbose_name
        db_table = "momself_live_group"


class LiveImMsg(models.Model):
    # live = models.ForeignKey(Live)
    group = models.ForeignKey(LiveGroup, related_name="group")
    types = models.PositiveSmallIntegerField("群组类型", default=3)  # 0:public 1:Private 2:ChatRoom 3:AVChatRoom
    from_account = models.ForeignKey(Student, related_name="msg_user")  # 消息发送者
    msg_time = models.CharField("消息的时间", max_length=30)
    msg_seq = models.IntegerField("消息的序列号")
    msg_body = models.TextField("消息体")
    online_onlyflag = models.PositiveSmallIntegerField("在线消息", default=0)  # 在线消息，为1，否则为0；直播群忽略此属性，为默认值0
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveImMsg()

    class Meta:
        verbose_name = '直播im消息(回调-异步)'
        verbose_name_plural = verbose_name
        db_table = "momself_liveim_msg"


class LiveImUser(models.Model):
    # live = models.ForeignKey(Live)
    group = models.ForeignKey(LiveGroup)
    student = models.ForeignKey(Student, related_name="group_user")
    watch_time = models.IntegerField("用户观看直播时长", default=0, blank=True)
    channel = models.PositiveSmallIntegerField("来源渠道", default=0, blank=True)
    like = models.IntegerField("点赞", default=0, blank=True)
    is_forbidden = models.PositiveSmallIntegerField("是否禁言", default=0)  # 0：否，1：是
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)
    # leave_at = models.DateTimeField("离开直播间时间", auto_now_add=True)

    objects = ModelManagerLiveImUser()

    class Meta:
        verbose_name = '直播im用户'
        verbose_name_plural = verbose_name
        db_table = "momself_liveim_user"


class LiveTally(models.Model):
    live = models.ForeignKey(Live)
    group = models.ForeignKey(LiveGroup)
    student = models.ForeignKey(Student, related_name='tally')
    # goods = models.ForeignKey(Role, null=True, blank=True)
    types = models.PositiveSmallIntegerField("类型", default=0)  # 0:购物袋点击  1:转发点击
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveTally()

    class Meta:
        verbose_name = '直播购物袋点击率(异步)'
        verbose_name_plural = verbose_name
        db_table = "momself_live_shopping_click"


class LiveInvitationUser(models.Model):
    live = models.ForeignKey(Live)
    invitation = models.ForeignKey(Student, related_name='invitation')  # 邀请人
    be_invited = models.ForeignKey(Student, related_name='be_invited')  # 受邀
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveInvitationUser()

    class Meta:
        verbose_name = '直播分享邀请'
        verbose_name_plural = verbose_name
        db_table = "momself_live_invitation_user"


class LiveData(models.Model):
    live = models.ForeignKey(Live)
    uv = models.IntegerField("直播观看uv", default=0, blank=True)
    pv = models.IntegerField("直播观看pv", default=0, blank=True)
    playback_uv = models.IntegerField("直播回放观看uv", default=0, blank=True)
    playback_pv = models.IntegerField("直播回放观看pv", default=0, blank=True)
    length_of_time = models.IntegerField("直播时长", default=0, blank=True)  # 单位秒
    playback_of_time = models.IntegerField("直播回放时长", default=0, blank=True)  # 单位秒
    highest_online = models.IntegerField("同时最高在线", default=0, blank=True)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveData()

    class Meta:
        verbose_name = '该场直播的相关数据包含回放'
        verbose_name_plural = verbose_name
        db_table = "momself_live_data"


class LivePlayback(models.Model):
    live = models.ForeignKey(Live, related_name="playback")
    url = models.CharField("回放链接", max_length=200)
    start_time = models.IntegerField("录制文件起始时间戳")
    end_time = models.IntegerField("录制文件结束时间戳")
    duration = models.IntegerField("录制文件时长，单位秒", default=0)
    file_size = models.IntegerField("录制文件大小，单位字节", default=0)
    playback_pass = models.CharField("回放密码", max_length=20, default='', blank=True)
    file_id = models.CharField("点播 file ID", max_length=50)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLivePlayback()

    class Meta:
        verbose_name = '该场直播的回放'
        verbose_name_plural = verbose_name
        db_table = "momself_live_playback"


class LivePeopleFlow(models.Model):
    live = models.ForeignKey(Live, related_name="flow")
    student = models.ForeignKey(Student, related_name='flow_iuser')
    join_time = models.IntegerField("加入时间", default=0)  # 这里的加入时间为加入房间，此时的退出时间为0，等用户退出时才来更新此退出
    exit_time = models.IntegerField("退出时间", default=0)
    status = models.PositiveSmallIntegerField("状态", default=0)  # 0代表在线  1代表离线
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLivePeopleFlow()

    class Meta:
        verbose_name = '该场直播的人流量'
        verbose_name_plural = verbose_name
        db_table = "momself_live_people_flow"

class LiveFictitiousComment(models.Model):
    live = models.ForeignKey(Live)
    comment = models.TextField('虚拟消息')
    nick_name = models.CharField(max_length=30, null=True, blank=True, verbose_name="昵称")
    send_time = models.IntegerField('发送时间/秒', null=False, blank=False)
    created_at = models.DateTimeField("添加时间", auto_now_add=True)
    updated_at = models.DateTimeField("修改时间", auto_now=True)

    objects = ModelManagerLiveFictitiousComment()
    class Meta:
        verbose_name = '虚拟评论表'
        verbose_name_plural = verbose_name
        db_table = "momself_live_fictitious_comment"


mm_Live = Live.objects
mm_LiveGoods = LiveGoods.objects
mm_LiveGoodsSku = LiveGoodsSku.objects
mm_LiveImMsg = LiveImMsg.objects
mm_LiveImUser = LiveImUser.objects
mm_LiveTally = LiveTally.objects
mm_LiveGroup = LiveGroup.objects
mm_LiveInvitationUser = LiveInvitationUser.objects
mm_LiveData = LiveData.objects
mm_LivePlayback = LivePlayback.objects
mm_LivePeopleFlow = LivePeopleFlow.objects
mm_LiveFictitiousComment = LiveFictitiousComment.objects
